package com.xue;

import com.pi4j.Pi4J;
import com.pi4j.context.Context;
import com.pi4j.io.serial.*;

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Consumer;

/**
 * @author xuejingbao
 * @create 2023-10-12 14:45
 */
public class GpsForPi {

    private static class GpsForPiHolder {
        private static final GpsForPi INSTANCE = new GpsForPi();
    }

    private GpsForPi() {
    }

    public static GpsForPi getInstance() {
        return GpsForPiHolder.INSTANCE;
    }

    private Serial serial;
    private List<Consumer<byte[]>> listeners = new CopyOnWriteArrayList<>();
    private boolean reception;
    private ExecutorService executor;
    private ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

    public void init(String device) throws InterruptedException {
        Context context = Pi4J.newAutoContext();
        SerialConfigBuilder scb = Serial.newConfigBuilder(context);
        SerialConfig sc = scb.use_9600_N81()
                .dataBits_8()
                .parity(Parity.NONE)
                .stopBits(StopBits._1)
                .flowControl(FlowControl.NONE)
                .id("my-serial")
                .device(device)
                .provider("pigpio-serial")
                .build();
        serial = context.create(sc);
        open();
        reception = true;
        executor = Executors.newSingleThreadExecutor();
        messageSender();
    }

    private void open() throws InterruptedException {
        if (serial != null) {
            serial.open();
            // 同步等待端口的开启
            while (!serial.isOpen()) {
                Thread.sleep(250);
            }
        }
    }

    private void messageSender() {
        executor.execute(() -> {
            while (reception) {
                if (serial.available() > 0) {
                    serial.read(byteBuffer);
                    split(byteBuffer);
                } else {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }

        });
    }

    private void split(ByteBuffer buffer) {
        buffer.flip();
        for(int i = 0; i < buffer.limit(); i++) {
            // 遍历寻找分隔符
            // get(i)不会移动position
            if (buffer.get(i) == '\n') {
                // 缓冲区长度
                int length = i+1-buffer.position();
                ByteBuffer target = ByteBuffer.allocate(length);
                // 将前面的内容写入target缓冲区
                for(int j = 0; j < length; j++) {
                    // 将buffer中的数据写入target中
                    target.put(buffer.get());
                }
                // 打印结果
                target.flip();
                for (Consumer<byte[]> listener : listeners) {
                    listener.accept(target.array());
                }
            }
        }
        // 切换为写模式，但是缓冲区可能未读完，这里需要使用compact
        buffer.compact();
    }

    public void addListener(Consumer<byte[]> consumer) {
        if (!listeners.contains(consumer)) {
            listeners.add(consumer);
        }
    }

    public void removeListener(Consumer<byte[]> consumer) {
        listeners.remove(consumer);
    }

    public void sendMessage(byte[] msg) {
        serial.write(msg);
    }

    public void stop() {
        reception = false;
        executor.shutdown();
    }


}
